<!DOCTYPE html>
<html>
<head>
    <title>路径算法可视化</title>
    <link rel="stylesheet" href="axis.css">
</head>
<body>
    <div class="control-panel">
        <div class="input-group">
            <label>起点X:<input type="number" id="startX" value="1" min="0" max="19"></label>
            <label>起点Y:<input type="number" id="startY" value="1" min="0" max="19"></label>
            <label>终点X:<input type="number" id="endX" value="18" min="0" max="19"></label>
            <label>终点Y:<input type="number" id="endY" value="18" min="0" max="19"></label>
        </div>
        <div class="actions-group">
            <select id="algorithm">
                <option value="astar">A*算法</option>
                <option value="dijkstra">Dijkstra算法</option>
            </select>
            <button onclick="start()">开始寻路</button>
            <button onclick="generateNewMap()">随机地图</button>
            <button id="clearObstacles">一键清空障碍</button>
            <span id="time" class="time-display"></span>
            <button id="toggleOptimization">优化已经关闭</button>
        </div>
        <input type="file" id="mapUpload" accept="image/*" style="display: none;">
        <button onclick="document.getElementById('mapUpload').click()">上传地图</button>
    </div>
    
    <div class="coordinate-system">
        <div class="y-axis"></div>
        <div class="x-axis"></div>
        <div id="grid" class="grid"></div>
    </div>

    <!-- 统计模块 -->
    <div class="stats-panel">
        <h3>性能统计</h3>
        <table id="statsTable">
            <thead>
                <tr>
                    <th>序号</th>
                    <th>算法</th>
                    <th>优化前时间(ms)</th>
                    <th>优化后时间(ms)</th>
                    <th>优化前步数</th>
                    <th>优化后步数</th>
                    <th>时长优化</th>
                    <th>步数差异</th>
                </tr>
            </thead>
            <tbody></tbody>
        </table>
        <div class="stats-actions">
        <button id="clearStats">清空统计</button>
        <button id="exportStats">导出CSV</button>
        </div>
    </div>

    <!-- 右键菜单 -->
    <div id="context-menu" class="context-menu">
        <ul>
            <li onclick="setAsStart()">设为起点</li>
            <li onclick="setAsEnd()">设为终点</li>
        </ul>
    </div>




    <!-- 脚本逻辑部分 -->
    <script src="grid.js"></script>
    <script src="pathfinding.js"></script>
    <script>
        const sizex=23,sizey=52;
        let grid = null;
        
        function init() {
            grid = new Grid(sizex, sizey);
            grid.draw();
            updateStartEndDisplay();
            //添加事件监听器（这部分应该在初始化代码中）
            document.getElementById('toggleOptimization').addEventListener('click', function() {
                enableOptimization = !enableOptimization;
                this.textContent = enableOptimization ? '优化已经开启' : '优化已经关闭';
            });
            // 添加清空障碍按钮事件监听器
            document.getElementById('clearObstacles').addEventListener('click', clearAllObstacles);
        }

        // 确保clearAllObstacles函数在全局作用域中
        function clearAllObstacles() {
            grid.clearAllObstacles();
            console.log("所有障碍已清除，地图已重置");
        }

        async function start() {
            // 强制刷新地图引用
            const cells = grid.getMapData(); 

            // 清除旧状态
            grid.clearVisualization();
            
            const startPos = validatePosition(
                parseInt(document.getElementById('startX').value),
                parseInt(document.getElementById('startY').value)
            );
            const endPos = validatePosition(
                parseInt(document.getElementById('endX').value),
                parseInt(document.getElementById('endY').value)
            );

            //连通块
            markConstraintArea(grid, startPos, endPos);

            // 更新紫色标记起终点
            grid.setStartEnd(startPos, endPos);
            
            const startTime = performance.now();
            const success = await findPath(grid, startPos, endPos, 
                document.getElementById('algorithm').value);
          
            document.getElementById('time').textContent = 
                `耗时: ${(performance.now() - startTime).toFixed(2)}ms | ${
                success ? '最短路长:'+success : '无可行路径'}`;
        }

        function validatePosition(x, y) {
            x = Math.max(0, Math.min(x, sizex));
            y = Math.max(0, Math.min(y, sizey));
            return {x, y};
        }

        function generateNewMap() {
            grid.generateRandomMap();
            grid.draw();
            updateStartEndDisplay();
        }

        function updateStartEndDisplay() {
            document.getElementById('startX').value = grid.start.x;
            document.getElementById('startY').value = grid.start.y;
            document.getElementById('endX').value = grid.end.x;
            document.getElementById('endY').value = grid.end.y;
        }

        init();

    // ====== 性能统计 ======
    let statsData = [];
    let currentMapHash = '';
    let currentTestId = 0;
    let lastAlgorithm = '';

    function generateMapHash(grid) {
        let hash = '';
        for (let x = 0; x < grid.rows; x++) {
            for (let y = 0; y < grid.cols; y++) {
                hash += grid.cells[x][y].isWall ? '1' : '0';
            }
        }
        return hash;
    }

    function getCurrentStatRecord(grid) {
        const newHash = generateMapHash(grid);
        const currentAlgorithm = document.getElementById('algorithm').value;
        
        if (newHash !== currentMapHash || currentAlgorithm !== lastAlgorithm) {
            currentMapHash = newHash;
            lastAlgorithm = currentAlgorithm;
            currentTestId++;
            
            statsData.push({
                id: currentTestId,
                algorithm: currentAlgorithm === 'astar' ? 'A*算法' : 'Dijkstra算法',
                mapHash: newHash,
                beforeTime: null,
                afterTime: null,
                beforeSteps: null,
                afterSteps: null,
                startPos: {...grid.start},
                endPos: {...grid.end}
            });
        }
        
        return statsData[statsData.length - 1];
    }

    function updateStatsTable() {
        const tbody = document.querySelector('#statsTable tbody');
        tbody.innerHTML = '';
        
        statsData.forEach(stat => {
            const row = document.createElement('tr');
            
            let timeImprovement = 'N/A';
            if (stat.beforeTime !== null && stat.afterTime !== null) {
                const improvement = ((stat.beforeTime - stat.afterTime) / stat.beforeTime * 100).toFixed(2);
                timeImprovement = `${improvement}%`;
            }
            
            let stepsDiff = 'N/A';
            if (stat.beforeSteps !== null && stat.afterSteps !== null) {
                stepsDiff = stat.afterSteps - stat.beforeSteps;
            }
            
            row.innerHTML = `
                <td>${stat.id}</td>
                <td>${stat.algorithm}</td>
                <td>${stat.beforeTime !== null ? stat.beforeTime.toFixed(2) : 'NULL'}</td>
                <td>${stat.afterTime !== null ? stat.afterTime.toFixed(2) : 'NULL'}</td>
                <td>${stat.beforeSteps !== null ? stat.beforeSteps : 'NULL'}</td>
                <td>${stat.afterSteps !== null ? stat.afterSteps : 'NULL'}</td>
                <td>${timeImprovement}</td>
                <td class="steps-diff">${stepsDiff !== 'N/A' ? stepsDiff : 'N/A'}</td>
            `;
            
            if (stepsDiff !== 'N/A') {
                const stepsDiffCell = row.querySelector('.steps-diff');
                if (stepsDiff > 0) {
                    stepsDiffCell.style.color = 'red';
                    stepsDiffCell.textContent = `+${stepsDiff}`;
                } else if (stepsDiff < 0) {
                    stepsDiffCell.style.color = 'green';
                }
            }
            
            tbody.appendChild(row);
        });
    }

    // start函数
    async function start() {
        grid.clearVisualization();
        
        const startPos = validatePosition(
            parseInt(document.getElementById('startX').value),
            parseInt(document.getElementById('startY').value)
        );
        const endPos = validatePosition(
            parseInt(document.getElementById('endX').value),
            parseInt(document.getElementById('endY').value)
        );
        
        grid.setStartEnd(startPos, endPos);
        
        const currentStat = getCurrentStatRecord(grid);
        const isOptimized = document.getElementById('toggleOptimization').textContent.includes('开启');
        
        const startTime = performance.now();
        const steps = await findPath(grid, startPos, endPos, 
            document.getElementById('algorithm').value);
        const elapsedTime = performance.now() - startTime;
        
        if (isOptimized) {
            currentStat.afterTime = elapsedTime;
            currentStat.afterSteps = steps;
        } else {
            currentStat.beforeTime = elapsedTime;
            currentStat.beforeSteps = steps;
        }
        
        updateStatsTable();
        
        document.getElementById('time').textContent = 
            `${isOptimized ? '优化后' : '优化前'}: ${elapsedTime.toFixed(2)}ms (${steps}步)`;
    }
    
    //优化前后的统计数据结构
    document.getElementById('clearStats').addEventListener('click', () => {
        statsData = [];
        currentTestId = 0;
        currentMapHash = '';
        lastAlgorithm = '';
        updateStatsTable();
    });

    document.getElementById('exportStats').addEventListener('click', () => {
        const csvContent = "data:text/csv;charset=utf-8," +
            "序号,算法,起点X,起点Y,终点X,终点Y,优化前时间(ms),优化后时间(ms),优化前步数,优化后步数\n" +
            statsData.map(stat => 
                `${stat.id},${stat.algorithm},${stat.startPos.x},${stat.startPos.y},${stat.endPos.x},${stat.endPos.y},` +
                `${stat.beforeTime !== null ? stat.beforeTime.toFixed(2) : 'NULL'},` +
                `${stat.afterTime !== null ? stat.afterTime.toFixed(2) : 'NULL'},` +
                `${stat.beforeSteps !== null ? stat.beforeSteps : 'NULL'},` +
                `${stat.afterSteps !== null ? stat.afterSteps : 'NULL'}`
            ).join("\n");
        
        const encodedUri = encodeURI(csvContent);
        const link = document.createElement("a");
        link.setAttribute("href", encodedUri);
        link.setAttribute("download", `path_stats_${new Date().toISOString().slice(0,10)}.csv`);
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    });
    </script>
</body>
</html>